package com.lei.study.config;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * zookeeper实现配置中心
 *
 * @author 伍磊
 */
public class ZkConfig {

    public static Map<String, String> CONFIG = new HashMap<>();

    private CuratorFramework client;

    private static final String CONFIG_PATH = "/zkConfig";

    private static final String SEP = "/";

    public ZkConfig() {
        // 初始化
        client = CuratorFrameworkFactory.newClient("localhost:2181,localhost:2182,localhost:2183,localhost:2184",
                new RetryNTimes(3, 1000));
        client.start();

        // 判断CONFIG_PATH是否存在 不存在则创建
        try {
            Stat stat = client.checkExists().forPath(CONFIG_PATH);
            if (null == stat) {
                client.create().withMode(CreateMode.PERSISTENT).forPath(CONFIG_PATH);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // init()
        init();
    }

    private void init() {
        // 初始化CONFIG
        try {
            Stat stat = client.checkExists().forPath(CONFIG_PATH);
            if (null != stat) {
                List<String> pathList = client.getChildren().forPath(CONFIG_PATH);
                for (String path : pathList) {
                    // 获取完整path
                    String wholePath = CONFIG_PATH + SEP + path;
                    byte[] bytes = client.getData().forPath(wholePath);
                    CONFIG.put(path, new String(bytes));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 设置监听器 判断子节点的变化
        PathChildrenCache watch = new PathChildrenCache(client, CONFIG_PATH, true);
        watch.getListenable().addListener((client, event) -> {
            // 获取配置名称
            String path = event.getData().getPath();
            if (path.startsWith(CONFIG_PATH)) {
                path = path.replace(CONFIG_PATH + SEP, "");
            }

            // 获取配置值
            String value = new String(event.getData().getData());

            // 根据不同事件进行处理
            PathChildrenCacheEvent.Type type = event.getType();
            if (PathChildrenCacheEvent.Type.CHILD_ADDED.equals(type)) {
                // 新增事件
                CONFIG.put(path, value);
            } else if (PathChildrenCacheEvent.Type.CHILD_UPDATED.equals(type)) {
                // 更新事件
                CONFIG.put(path, value);
            } else if (PathChildrenCacheEvent.Type.CHILD_REMOVED.equals(type)) {
                // 删除事件
                CONFIG.remove(path);
            }
        });
    }

    /**
     * 设置值
     * @param name
     * @param value
     * @return
     */
    public boolean setConfig(String name, String value) {
        String path = CONFIG_PATH + SEP + name;
        try {
            Stat stat = client.checkExists().forPath(path);
            if (null == stat) {
                // 创建
                client.create().withMode(CreateMode.PERSISTENT).forPath(path, value.getBytes());
            } else {
                // 更新
                client.setData().forPath(path, value.getBytes());
            }
            CONFIG.put(name, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 获取配置
     * @param name
     * @return
     */
    public String getConfig(String name) {
        return CONFIG.get(name);
    }
}
